package com.zh.common.view.shadow

import android.graphics.*
import android.os.Build
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import com.zh.common.R
import kotlin.math.max
import kotlin.math.min

/**
 * @Author: wt
 * @Date: 2021/9/29 14:22
 * @Des: 实现控件的阴影效果，可自定义颜色
 */
class ShadowHelper(private val view: View) {

    private var bgShadowBgColor = 0//背景颜色

    private var bgShadowBgEndColor = 0//背景渐变色

    private var bgShadowColor = 0//阴影颜色

    private var bgShadowLineColor = 0//边框颜色

    private var bgShadowLineWidth = 1F//边框宽度

    private var bgShadowRadius = 0F//背景阴影半径

    private var bgShadowRound = 0F//圆角半径

    private var bgShadowDx = 0F//背景阴影X偏移

    private var bgShadowDy = 0F//背景阴影Y偏移

    private var bgTriangleSize = 0F//绘制三角形

    private var bgTriangleProX = 0F//绘制三角形位置按宽度比例

    //true：父类切割外部阴影区域，子控件代码上通过减少宽高来绘制出阴影，此方案背景会小于设置效果的阴影半径，设置宽高的时候需要考虑将阴影半径加上
    //false：父类不切割外部阴影，子控件保存不变
    private var bgShadowParentClip = false

    //三角形路径
    private val trianglePath by lazy {
        Path()
    }

    //部分圆角矩形路径
    private val path by lazy {
        Path()
    }

    private val bgPaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = bgShadowBgColor
            if (bgShadowRadius > 0) {//阴影半径
                setShadowLayer(
                    bgShadowRadius * 0.8F,
                    bgShadowDx, bgShadowDy,
                    bgShadowColor
                )
            }
            style = Paint.Style.FILL
        }
    }

    private val linePaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            style = Paint.Style.STROKE
        }
    }

    /**
     * 初始化资源配置
     */
    fun initAttr(attrs: AttributeSet?, defStyleAttr: Int) {
        (view.parent as? ViewGroup)?.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
        val typedArray =
            view.context.obtainStyledAttributes(attrs, R.styleable.BgShadowView, defStyleAttr, 0)
        bgShadowBgColor = typedArray.getColor(R.styleable.BgShadowView_sv_bgShadowBgColor, 0)
        bgShadowBgEndColor = typedArray.getColor(R.styleable.BgShadowView_sv_bgShadowBgEndColor, 0)
        bgShadowColor = typedArray.getColor(R.styleable.BgShadowView_sv_bgShadowColor, bgShadowBgColor)
        bgShadowLineColor = typedArray.getColor(R.styleable.BgShadowView_sv_bgShadowLineColor, 0)
        bgShadowLineWidth = typedArray.getDimension(R.styleable.BgShadowView_sv_bgShadowLineWidth, 1F)
        bgShadowRadius = typedArray.getDimension(R.styleable.BgShadowView_sv_bgShadowRadius, 0F)
        bgShadowRound = typedArray.getDimension(R.styleable.BgShadowView_sv_bgShadowRound, 0F)
        bgShadowDx = typedArray.getDimension(R.styleable.BgShadowView_sv_bgShadowDx, 0F)
        bgShadowDy = typedArray.getDimension(R.styleable.BgShadowView_sv_bgShadowDy, 0F)
        bgTriangleSize = typedArray.getDimension(R.styleable.BgShadowView_sv_bgTriangleSize, 0F)
        bgTriangleProX = typedArray.getFloat(R.styleable.BgShadowView_sv_bgTriangleProX, 0F)
        bgShadowParentClip =
            typedArray.getBoolean(R.styleable.BgShadowView_sv_bgShadowParentClip, false)
        typedArray.recycle()
    }

    fun onAttachedToWindow() {
        //设置了父类不切割
        if (bgShadowColor != 0 && bgShadowRadius > 0 && !bgShadowParentClip) {
            val parent = view.parent
            if (parent is ViewGroup) {
                parent.clipChildren = false
                parent.clipToPadding = false
            }
        }
    }

    /**
     * 开始绘制阴影
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun drawShadow(canvas: Canvas?) {
        canvas ?: return
        if (bgShadowBgColor == 0) return//没有颜色不绘制
        val width = view.width.toFloat()
        val height = view.height.toFloat()

        if (bgShadowParentClip) {
            canvas.drawRoundRect(
                bgShadowRadius - bgShadowDx, bgShadowRadius - bgShadowDy + bgTriangleSize,
                width - bgShadowRadius - bgShadowDx, height - bgShadowRadius - bgShadowDy,
                bgShadowRound, bgShadowRound, bgPaint
            )
            canvas.translate(-bgShadowDx, -bgShadowDy)
        } else {
            if (bgShadowBgEndColor != 0) {
                bgPaint.shader = LinearGradient(
                    0F, 0F, width, 0F,
                    bgShadowBgColor, bgShadowBgEndColor, Shader.TileMode.CLAMP
                )
            }
            canvas.drawRoundRect(
                0F, bgTriangleSize / 2,
                width, height,
                bgShadowRound, bgShadowRound, bgPaint
            )
            if (bgShadowLineColor != 0) {//绘制边框
                linePaint.color = bgShadowLineColor
                linePaint.strokeWidth = bgShadowLineWidth
                canvas.drawRoundRect(
                    0F, bgTriangleSize / 2,
                    width, height,
                    bgShadowRound, bgShadowRound, linePaint
                )
            }
        }

        if (bgTriangleSize > 0) {//绘制三角形
            trianglePath.reset()
            val tLeft = min(
                width * bgTriangleProX + bgShadowRound,
                width - bgTriangleSize - bgShadowRound
            )
            trianglePath.moveTo(tLeft, bgTriangleSize / 2 + 1)
            trianglePath.rLineTo(bgTriangleSize / 2, -bgTriangleSize / 2)
            trianglePath.rLineTo(bgTriangleSize / 2, bgTriangleSize / 2)
            canvas.drawPath(trianglePath, bgPaint)
            if (bgShadowLineColor != 0) {
                canvas.drawPath(trianglePath, linePaint)
            }
        }
    }

    fun setShadowBgColor(bgColor: Int) {
        bgShadowBgColor = bgColor
        bgPaint.color = bgColor
    }

    fun setShadowLineColor(lineColor: Int) {
        bgShadowLineColor = lineColor
    }

    fun setShadowLineWidth(lineWidth: Float) {
        bgShadowLineWidth = lineWidth
    }

    fun setTriangleProX(proX: Float) {
        bgTriangleProX = proX
    }

    /**
     * 部分圆角矩形实现
     */
    private fun drawPartPath(tl: Float, tr: Float, br: Float, bl: Float) {
        path.reset()
        val width = view.width.toFloat()
        val height = view.height.toFloat()
        val rMax = width.coerceAtMost(height) / 2F
        val topLeft = min(max(tl, 0F), rMax)
        val topRight = min(max(tr, 0F), rMax)
        val bottomRight = min(max(br, 0F), rMax)
        val bottomLeft = min(max(bl, 0F), rMax)
        path.moveTo(width, topRight)
        if (topRight > 0)
            path.rQuadTo(0f, -topRight, -topRight, -topRight)//右上角
        else {
            path.rLineTo(0f, -topRight)
            path.rLineTo(-topRight, 0f)
        }
        path.rLineTo(-(width - topRight - topLeft), 0f)
        if (topLeft > 0)
            path.rQuadTo(-topLeft, 0f, -topLeft, topLeft) //左上角
        else {
            path.rLineTo(-topLeft, 0f)
            path.rLineTo(0f, topLeft)
        }
        path.rLineTo(0f, height - topLeft - bottomLeft)

        if (bottomLeft > 0)
            path.rQuadTo(0f, bottomLeft, bottomLeft, bottomLeft)//左下角
        else {
            path.rLineTo(0f, bottomLeft)
            path.rLineTo(bottomLeft, 0f)
        }

        path.rLineTo(width - bottomLeft - bottomRight, 0f)
        if (bottomRight > 0)
            path.rQuadTo(bottomRight, 0f, bottomRight, -bottomRight) //右下角
        else {
            path.rLineTo(bottomRight, 0f)
            path.rLineTo(0f, -bottomRight)
        }

        path.rLineTo(0f, -(height - bottomRight - topRight))

        path.close()
    }

}